package cn.com.sinux.spring.utils.fileconvert;

import cn.com.sinux.spring.exception.ServiceException;
import cn.com.sinux.spring.utils.FileUtils;
import com.artofsolving.jodconverter.DefaultDocumentFormatRegistry;
import com.artofsolving.jodconverter.DocumentConverter;
import com.artofsolving.jodconverter.DocumentFormat;
import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

/**
 * Created by Administrator on 2016/10/6.
 */
public class OpenOfficeConvertEngine extends ConvertEngine {

    private static final Logger logger = LoggerFactory.getLogger(OpenOfficeConvertEngine.class);
    private String openOffieHome;
    private int port;

    public OpenOfficeConvertEngine(String openOffieHome, int port) {
        this.openOffieHome = openOffieHome;
        this.port = port;
    }

    private File getPdfFiles(String destPath){
        File file = new File(destPath);
        Collection<File> files = FileUtils.listFiles(file, new String[]{"pdf"}, false);
        return files.isEmpty() ? null : files.iterator().next();
    }

    private String getPath(ConvertObject convertObject){
        String extName = FileUtils.getExtName(convertObject.getSource());
        String dest;
        if ("pdf".equals(extName.toLowerCase())) {
            dest = convertObject.getSource();
        }else{
            File file = getPdfFiles(convertObject.getDesDir());
            if(file == null){
                office2PDF(openOffieHome, port, convertObject, "pdf");
                dest = convertObject.getDesDir() + "/" + convertObject.getResults().get(0);
            }else{
                dest = file.getPath();
            }
        }
        return dest;
    }


    public void convert(ConvertType convertType, ConvertObject convertObject) throws Exception {
        String extName = FileUtils.getExtName(convertObject.getSource());
        if (StringUtils.isBlank(extName)) {
            logger.error("不能转换的类型");
            convertObject.failure("不能转换的类型");
            return;
        }
        if (ConvertType.toPdf.equals(convertType)) {
            if (ConvertResultType.PDF.name().equals(extName.toUpperCase())) {
                File file = new File(convertObject.getSource());
                //如果存在，则直接拷贝一个资源过去
                String dsName = UUID.randomUUID().toString() + ".pdf";
                FileUtils.copy(file, new File(convertObject.getDesDir() + "/" + dsName), false);
                convertObject.success(Collections.singletonList(dsName));
                return;
            }
            office2PDF(openOffieHome, port, convertObject, "pdf");
        } else if (ConvertType.toImage.equals(convertType)) {
            //检查目标文件是否已经存在pdf，存在则不用再抓换
            //判断文件如果是pdf文件则直接直接转换
            String dest = getPath(convertObject);
            convertObject.success(convertToImage(dest, convertObject.getDesDir()));
        } else if (ConvertType.toSwf.equals(convertType)) {
            //检查目标文件是否已经存在pdf，存在则不用再抓换
            String dest = getPath(convertObject);
            convertObject.success(convertToSwf(dest, convertObject.getDesDir()));
        } else {
            convertToHtml(convertObject);
        }
    }

    private void convertToHtml(ConvertObject convertObject) throws Exception {
        office2PDF(openOffieHome, port, convertObject, "html");
    }

    private String convertToSwf(String source, String dest) throws Exception {
        return pdf2Swf(source, dest, true);
    }

    private List<String> convertToImage(String source, String dest) throws Exception {
        return pdf2Img(source, dest);
    }

    private DocumentFormat toDocumentFormat(String path) {
        String docType = FileUtils.getExtName(path).toLowerCase();
        DefaultDocumentFormatRegistry _formatReg = new DefaultDocumentFormatRegistry();
        if (ConvertEngine.DocType.pptx.name().equals(docType)) {
            return _formatReg.getFormatByFileExtension(ConvertEngine.DocType.ppt.name());
        } else if (ConvertEngine.DocType.docx.name().equals(docType)) {
            return _formatReg.getFormatByFileExtension(ConvertEngine.DocType.doc.name());
        } else if (ConvertEngine.DocType.xlsx.name().equals(docType)) {
            return _formatReg.getFormatByFileExtension(ConvertEngine.DocType.xls.name());
        }
        return null;
    }


    private static boolean doConnect(OpenOfficeConnection connection) {
        if (connection.isConnected()) {
            return true;
        }
        int i = 0;
        boolean connected = false;
        while (i < 3 && !connected) {
            try {
                if (i > 0) {
                    LoggerFactory.getLogger(OpenOfficeConvertEngine.class).debug("再次连接openOffice，已连接次数{}", i + 1);
                }
                connection.connect();
                LoggerFactory.getLogger(OpenOfficeConvertEngine.class).debug("连接openOffice成功");
                connected = connection.isConnected();
            } catch (Exception ex) {
                i++;
                System.out.print(ex.getMessage());
                LoggerFactory.getLogger(OpenOfficeConvertEngine.class).debug("连接openOffice失败，失败原因：{}", ex.getMessage());
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    System.out.print(e.getMessage());
                }
            }
        }
        return connected;
    }

    private synchronized void office2PDF(String openOffieHome, int port, ConvertObject convertObject, String result) {
        OpenOfficeConnection connection = null;
        Process proc = null;
        try {

            if (StringUtils.isBlank(openOffieHome)) {
                throw new ServiceException("没有配置正确的openoffice路径，转换失败！");
            }
            // 启动OpenOffice的服务
            String command = openOffieHome
                    + "/program/soffice.exe -headless -accept=\"socket,host=127.0.0.1,port=" + port + ";urp;\"";
            System.out.print(command);
            LoggerFactory.getLogger(OpenOfficeConvertEngine.class).debug("文件转换的命令{}", command);
            proc = Runtime.getRuntime().exec(command);
            connection = new SocketOpenOfficeConnection(
                    "127.0.0.1", port);
            LoggerFactory.getLogger(OpenOfficeConvertEngine.class).debug("开始连接");
            if (!doConnect(connection)) {
                throw new ServiceException("没有能够有效启用openoffice，转换失败！");
            }
            LoggerFactory.getLogger(OpenOfficeConvertEngine.class).debug("连接成功，开始转换");
            DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
            DocumentFormat formatReg = new DefaultDocumentFormatRegistry().getFormatByFileExtension("pdf");

            File inputFile = new File(convertObject.getSource());
            if (!inputFile.exists()) {
                LoggerFactory.getLogger(OpenOfficeConvertEngine.class).error("文件不存在，不能转换{}", convertObject.getSource());
                convertObject.failure("文件不存在，不能转换");
                return;
            }
            File dest = new File(convertObject.getDesDir() + "/" + UUID.randomUUID().toString() + "." + result);
            converter.convert(inputFile, toDocumentFormat(convertObject.getSource()), dest, formatReg);
            convertObject.success(dest.getName());
        } catch (Exception e) {
            e.printStackTrace();
            LoggerFactory.getLogger(OpenOfficeConvertEngine.class).error("文件转换出现错误{}", e.getMessage());
        } finally {
            if (connection != null && connection.isConnected()) {
                connection.disconnect();
                connection = null;
            }
            if (proc != null) {
                proc.destroy();
                proc = null;
            }
        }
    }

}
